package application;

import controleur.ConstantesWeb;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.List;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class Facade {

    /**
     * Cette fonction créer les cookies pour identifier un utilisateur.
     * @param user le nom de l'utlisateur
     * @param pwd le mot de passe de l'utlisateur
     * @param res le ServletResponse
     * @return l'état de réussite de la création des cookies d'identification.
     */
    public boolean creerCookiesIdentification(final String user, final String pwd, final HttpServletResponse res) {
        List<MembreBean> mbean = MembreDAO.getMembre(user, pwd);
        return creerCookiesIdentification(mbean, res);
    }

    /**
     * Cette méthode enlève les cookies d'identification d'un utilisateur.
     * @param req le ServletRequest
     * @param res le ServletResponse
     */
    public void enleverCookiesIdentification(final HttpServletRequest req, final HttpServletResponse res) {
        Cookie[] cookies = req.getCookies();

        for (int i = 0; i < cookies.length; i++) {
            if (cookies[i].getName().equals(ConstantesWeb.COOKIE_MEMBRE_NOM_UTILISATEUR)
                    || cookies[i].getName().equals(ConstantesWeb.COOKIE_MEMBRE_MOT_PASSE)) {
                cookies[i].setMaxAge(0);
                res.addCookie(cookies[i]);
            }
        }
    }

    /**
     * Cette fonction trouve un membre selon les cookies.
     * @param cookies les cookies de la page web
     * @return un membre
     */
    public MembreBean getMembre(final Cookie[] cookies) {
        String nomUtilisateur = "";
        String motPasse = "";
        MembreBean mBean = null;
        List<MembreBean> membresBeanListe;

        if (cookies == null) {
            return null;
        }
        
        for (int i = 0; i < cookies.length; i++) {
            if (cookies[i].getName().equals(ConstantesWeb.COOKIE_MEMBRE_NOM_UTILISATEUR)) {
                nomUtilisateur = cookies[i].getValue();
            } else if (cookies[i].getName().equals(ConstantesWeb.COOKIE_MEMBRE_MOT_PASSE)) {
                motPasse = cookies[i].getValue();
            }
        }

        if (!nomUtilisateur.equals("") && !motPasse.equals("")) {
            membresBeanListe = MembreDAO.getMembre(nomUtilisateur, motPasse);

            if (!membresBeanListe.isEmpty()) {
                return membresBeanListe.get(0);
            }
        }

        return null;
    }

    /**
     * Cette fonction trouve un mebre selon son identifiant.
     * @param idMembre l'identifiant du membre
     * @return un membre
     */
    public MembreBean getMembre(final String idMembre) {
        List<MembreBean> membresBeanListe = MembreDAO.getMembre(idMembre);

        if (membresBeanListe.isEmpty()) {
            return null;
        } else {
            return membresBeanListe.get(0);
        }
    }
    
    /**
     * Cette fonction trouve un membre selon son nom d'utilisateur.
     * @param nomUtilisateur le nom d'utilisateur du membre
     * @return un membre
     */
    public MembreBean getMembreUtilisateur(final String nomUtilisateur) {
        List<MembreBean> membresBeanListe = MembreDAO.getMembreUtilisateur(nomUtilisateur);

        if (membresBeanListe.isEmpty()) {
            return null;
        } else {
            return membresBeanListe.get(0);
        }
    }

    /**
     * Cette fonction trouve tous les livres.
     * @return une collection de livres
     */
    public List<LivreBean> getLivres() {
        return LivreDAO.getLivres();
    }

    /**
     * Cette fonction trouve la cote moyenne d'un livre.
     * @param isbn l'isbn du livre
     * @return  la cote moyenne d'un livre
     */
    public String getCoteMoyenne(final String isbn) {
        return CritiqueDAO.getCoteMoyenne(isbn);
    }

    /**
     * Cette fonction trouve les critiques d'un livre.
     * @param isbn l'isbn du livre
     * @return une collection de livre
     */
    public List<CritiqueBean> getCritiqueLivres(final String isbn) {
        List<CritiqueBean> critiquesBeanListe = CritiqueDAO.getCritiquesLivre(isbn);

        return critiquesBeanListe;
    }

    /**
     * Cette fonction vérifie si un membre à écrit une critique pour un livre.
     * @param isbn l'isbn du livre
     * @param idMembre l'identifiant du membre
     * @return l'existance d'une critique d'un livre par un membre.
     */
    public boolean verifierCritiqueExiste(final String isbn, final String idMembre) {
        List<CritiqueBean> critiquesBeanListe = CritiqueDAO.getCritiqueMembre(isbn, idMembre);
        boolean critiqueExiste = true;

        if (critiquesBeanListe.isEmpty()) {
            critiqueExiste = false;
        }

        return critiqueExiste;
    }

    /**
     * Cette fonction trouve un livre.
     * @param isbn l'isbn du livre
     * @return un livre
     */
    public LivreBean getLivre(final String isbn) {
        List<LivreBean> livresBeanListe = LivreDAO.getLivre(isbn);

        if (livresBeanListe.isEmpty()) {
            return null;
        } else {
            return livresBeanListe.get(0);
        }
    }

    /**
     * Cette fonction trouvre tous les auteurs.
     * @return une collection d'auteurs
     */
    public List<AuteurBean> getAuteurs() {
        return AuteurDAO.getAuteurs();
    }

    /**
     * Cette fonction trouve une ville et son pays.
     * @param idVille l'identifiant d'une ville
     * @return une ville avec son pays
     */
    public VillePaysBean getVillePays(final String idVille) {
        List<VillePaysBean> villesPaysBeanListe = VillePaysDAO.getVillePays(idVille);

        if (villesPaysBeanListe.isEmpty()) {
            return null;
        } else {
            return villesPaysBeanListe.get(0);
        }
    }

    /**
     * Cette fonction trouve un auteur selon don identifiant.
     * @param idAuteur l'identifiant de l'auteur
     * @return un auteur
     */
    public AuteurBean getAuteur(final String idAuteur) {
        List<AuteurBean> auteursBeanListe = AuteurDAO.getAuteur(idAuteur);

        if (auteursBeanListe.isEmpty()) {
            return null;
        } else {
            return auteursBeanListe.get(0);
        }
    }

    /**
     * Cette fonction trouve un auteur selon son livre.
     * @param isbn l'isbn d'un livre
     * @return un auteur
     */
    public AuteurBean getAuteurLivre(final String isbn) {
        List<AuteurBean> auteursBeanListe = AuteurDAO.getAuteurLivre(isbn);

        return auteursBeanListe.get(0);
    }

    /**
     * Cette fonction trouve tous les livres d'un auteur
     * @param idAuteur l'identifiant de l'auteur
     * @return une collect de livres
     */
    public List<LivreBean> getLivresAuteurListe(String idAuteur) {
        return LivreDAO.getLivresAuteurListe(idAuteur);
    }

    /**
     * Cette fonction trouve une description de la table Type selon son identifiant.
     * @param id l'identifiant de la description
     * @return une description de la table Type
     */
    public String getTypeValeur(final String id) {
        return TypeDAO.getValeur(id);
    }

    /**
     * Cette fonction trouve une description de la table Type selon sa valeur.
     * @param valeur la valeur de la description
     * @return une description de la table Type
     */
    public String getTypeId(final String valeur) {
        return TypeDAO.getId(valeur);
    }

    /**
     * Cette fonction trouve une ville et son pays.
     * @return une ville avec son pays
     */
    public List<VillePaysBean> getVillesPays() {
        return VillePaysDAO.getVillesPays();
    }

    /**
     * Cette fonction écrit une critique.
     * @param c une critique
     * @return le nombre de colonnes affectées
     */
    public int ecrireCritique(final CritiqueBean c) {
        return CritiqueDAO.ecrireCritique(c);
    }

    /**
     * Cette fonction supprime une critique. 
     * @param idCritique l'identifiant de la critique
     * @return le nombre de colonnes affectées
     */
    public int supprimerCritique(final String idCritique) {
        return CritiqueDAO.supprimerCritique(idCritique);
    }

    /**
     * Cette fonction trouve une image selon son identifiant.
     * @param id l'identifiant de l'image
     * @return une image
     */
    public ImageBean getImage(final String id) {
        List<ImageBean> imagesBeanListe = ImageDAO.getImage(id);

        if (imagesBeanListe.isEmpty()) {
            return null;
        } else {
            return imagesBeanListe.get(0);
        }
    }

    /**
     * Cette fonction met à jour un membre.
     * @param req le ServletRequest
     * @param res le ServletResponse
     * @return le nombre de colonnes affectées
     */
    public int updateMembre(final HttpServletRequest req, final HttpServletResponse res) {
        int rowResults = 0;
        MembreBean m = creerMembreModifie(req);

        rowResults = MembreDAO.updateMembre(m);

        if (rowResults != 0) {
            creerCookiesIdentification(m.getNomUtilisateur(), m.getMotPasse(), res);
        }
        return rowResults;
    }
    
    /**
     * Cette fonction crée un FileInputStream d'un fichier.
     * @param fichier la location du fichier
     * @return le FileInputStream du fichier
     * @throws FileNotFoundException une erreur est causée si le fichier
     * n'existe pas
     */
    public FileInputStream creerFichier(final String fichier) throws FileNotFoundException {
        File f = new File(fichier);
        FileInputStream fin = new FileInputStream(f);

        return fin;
    }

    /**
     * Cette fonction change l'image de profil d'un membre.
     * @param fin l'image en format FileInputStream
     * @param idMembre l'identifiant du membre
     * @return le nombre de colonnes affectées
     */
    public int updateImage(final FileInputStream fin, final String idMembre) {
        int rowResults = ImageDAO.updateImage(fin, idMembre);

        return rowResults;
    }

    /**
     * Cette fonction trouve tous le commendes ouvertes d'un membre.
     * @param idMembre l'identifiant du membre
     * @return une collection de commandes
     */
    public List<CommandeBean> getCommandesOuvertesMembre(String idMembre) {
        List<CommandeBean> commandesBeanListe = CommandeDAO.getCommandesOuvertesMembre(idMembre);

        for (CommandeBean c : commandesBeanListe) {
            c.setEmprunts(getLivresCommandes(c.getIdCommande()));
            c.setFacture(calculerFacture(c.getNombreJoursRetard(), c.getEmprunts()));
        }

        return commandesBeanListe;
    }

    /**
     * Cete fonction calcule la facture totale d'un membre.
     * @param commandesListe les commandes ouvertes d'un membre
     * @return le total de la facture d'un membre
     */
    public double calculerFactureTotale(final List<CommandeBean> commandesListe) {
        double factureTotale = 0;

        for (CommandeBean c : commandesListe) {
            factureTotale += c.getFacture();
        }
        return factureTotale;
    }

    /**
     * Cette fonction trouve tous les commandes ouvertes.
     * @return une collection de commandes
     */
    public List<CommandeBean> getCommandesOuvertes() {
        List<CommandeBean> commandesBeanListe = CommandeDAO.getCommandesOuvertes();

        for (CommandeBean c : commandesBeanListe) {
            c.setEmprunts(getLivresCommandes(c.getIdCommande()));
            c.setFacture(calculerFacture(c.getNombreJoursRetard(), c.getEmprunts()));
        }

        return commandesBeanListe;
    }

    /**
     * Cette fonction trouve tous les membres.
     * @return une collection de membres
     */
    public List<MembreBean> getMembres() {
        return MembreDAO.getMembres();
    }

    /**
     * Cette fonction vérifie si un nom d'utilisateur existe dans la base de
     * données.
     * @param nomUtilisateur le nom de l'utilisateur
     * @return l'existance ou nom d'un nom d'utilisateur
     */
    public boolean verifierNomUtilisateurExiste(final String nomUtilisateur) {
        boolean nomUtilisateurExiste = true;
        List<MembreBean> membresBeanListe;

        membresBeanListe = MembreDAO.getMembreUtilisateur(nomUtilisateur);

        if (membresBeanListe.isEmpty()) {
            nomUtilisateurExiste = false;
        }
        return nomUtilisateurExiste;
    }

    /**
     * Cette fonction creer un nouveau membre
     * @param req le ServletRequest
     * @param idCompte l'identifiant du membre
     * @return le nombre de colonnes affectées
     */
    public int creerCompte(final HttpServletRequest req, 
            final String idCompte) {
        MembreBean m = creerNouveauMembre(req, idCompte);
        int rowCount = 0;
        
        rowCount = MembreDAO.creerMembre(m);
        
        return rowCount;
    }
  
    /**
     * Cette fonction crée l'image d'un membre.
     * @param fin l'image en format de FileInputStream
     * @param idMembre l'identifiant d'un membre
     * @return le nombre de colonnes affectées
     */
    public int creerImageMembre(final FileInputStream fin, final String idMembre) {
        int rowCount = 0;
        
        rowCount = ImageDAO.creerImage(fin, idMembre);
        
        return rowCount;
    }
    
    /**
     * Cette fonction associe une image à son membre.
     * @param idMembre l'identifiant du membre
     * @return le nombre de colonnes affectées
     */
    public int associerImageMembre(final String idMembre) {
        String idImage;
        int rowCount = 0;
        
        idImage = ImageDAO.getImageMembre(idMembre).get(0).getId();
        rowCount = ImageDAO.associerImageMembre(idMembre, idImage);
        
        return rowCount;
    }

    /**
     * Cette  fonction calcule une facture de client.
     * @param nombreJoursRetard le nombre de jours de retard
     * @param emprunts une collection des livres empruntés
     * @return le coût d'une facture
     */
    private double calculerFacture(int nombreJoursRetard, final List<LivreBean> emprunts) {
        double facture = 0;
        double coutParJour = 0;

        if (nombreJoursRetard <= ConstantesWeb.NOMBRES_JOUR_1) {
            coutParJour = ConstantesWeb.COUT_PAR_JOUR_1;
        } else if (nombreJoursRetard <= ConstantesWeb.NOMBRES_JOUR_2) {
            coutParJour = ConstantesWeb.COUT_PAR_JOUR_2;
            facture += calculerCoutBase(ConstantesWeb.COUT_BASE_2, emprunts.size());
        } else {
            coutParJour = ConstantesWeb.COUT_PAR_JOUR_3;
            facture += calculerCoutBase(ConstantesWeb.COUT_BASE_3, emprunts.size());
            facture += calculerCoutRemplacement(emprunts);
        }
        facture += calculerFactureCommande(nombreJoursRetard, coutParJour, emprunts.size());

        return facture;
    }

    /**
     * Cette fonction calcule la facture d'une commande.
     * @param nombreJours le nombre de jours de retard
     * @param coutParJour le coût par jour
     * @param nombreLivresEmpruntes le nombre de livres empruntés
     * @return le coût d'une facture
     */
    private double calculerFactureCommande(final int nombreJours, final double coutParJour, final int nombreLivresEmpruntes) {
        return nombreJours * coutParJour * nombreLivresEmpruntes;
    }

    /**
     * Cete fonction calcule le coût de base.
     * @param coutBase valeur du coût de base
     * @param nombreLivresEmpruntes le nombre de livres empruntés
     * @return le coût de base total
     */
    private double calculerCoutBase(final double coutBase, final int nombreLivresEmpruntes) {
        return coutBase * nombreLivresEmpruntes;
    }

    /**
     * Cette fonction calcule le coût de remplacement.
     * @param emprunts une collection des livres empruntés
     * @return le coût de remplacement
     */
    private double calculerCoutRemplacement(final List<LivreBean> emprunts) {
        double coutRemplacementTotal = ConstantesWeb.COUT_ADMINISTRATIVES;
        double coutRemplacement;


        for (LivreBean e : emprunts) {
            try {
                coutRemplacement = Double.parseDouble(e.getCoutRemplacement());
            } catch (NumberFormatException ex) {
                coutRemplacement = ConstantesWeb.COUT_ADMINISTRATIVES;
            }
            coutRemplacementTotal += coutRemplacement;
        }
        return calculerTaxes(coutRemplacementTotal);
    }

    /**
     * Cette fonction calcule les taxes.
     * @param montant le coût avant les taxes
     * @return le coût après les taxes
     */
    private double calculerTaxes(final double montant) {
        double montantAvecTPS;
        double montantTotal;

        montantAvecTPS = montant + montant * ConstantesWeb.TPS;
        montantTotal = montantAvecTPS + montantAvecTPS * ConstantesWeb.TVQ;

        return montantTotal;
    }

    /**
     * Cette fonction trouve les livres d'une commande.
     * @param idCommande l'identifiant d'une commande
     * @return une collection de livre
     */
    private List<LivreBean> getLivresCommandes(final String idCommande) {
        return LivreDAO.getLivresCommande(idCommande);
    }

    /**
     * Cette fonction crée les cookies d'identification.
     * @param mbean un membre
     * @param res le ServletResponse
     * @return le succès ou non de la création des cookies d'un membre
     */
    private boolean creerCookiesIdentification(final List<MembreBean> mbean, final HttpServletResponse res) {
        try {
            if (mbean != null && !mbean.isEmpty()) {
                res.addCookie(new Cookie(ConstantesWeb.COOKIE_MEMBRE_NOM_UTILISATEUR, mbean.get(0).nomUtilisateur));
                res.addCookie(new Cookie(ConstantesWeb.COOKIE_MEMBRE_MOT_PASSE, mbean.get(0).motPasse));
                return true;
            }
        } catch (Exception e) {
            System.err.println("Error in creerCookiesIdentification: " + e);
        }
        return false;
    }

    /**
     * Cette fonction crée un membre modifié.
     * @param req le ServletRequest
     * @return un membre
     */
    private MembreBean creerMembreModifie(final HttpServletRequest req) {
        Membre m;
        String nouveauMotPasse;

        if (!req.getParameter("pwd-nouveau-1").equals("")) {
            nouveauMotPasse = req.getParameter("pwd-nouveau-1");
        } else {
            nouveauMotPasse = req.getParameter("pwd-ancien");
        }

        m = initialiserObjetMembre(req);
        m.setIdMembre(req.getParameter("idMembre"));
        m.setMotPasse(nouveauMotPasse);

        return m.getMembreBean();
    }

    /**
     * Cette fonction crée un nouveau membre
     * @param req le ServletRequest
     * @param idCompte l'identifiant du membre
     * @return un membre
     */
    private MembreBean creerNouveauMembre(final HttpServletRequest req,
            final String idCompte) {
        Membre m;

        m = initialiserObjetMembre(req);
        m.setMotPasse(req.getParameter("pwd-nouveau-1"));
        m.setIdCompte(idCompte);
        m.setIdImage(null);

        return m.getMembreBean();
    }

    /**
     * Cette fonction initialise l'objet Membre
     * @param req le ServletRequest
     * @return un membre
     */
    private Membre initialiserObjetMembre(final HttpServletRequest req) {
        Membre m = new Membre();

        m.setAdresse(req.getParameter("adresse"));
        m.setCourriel(req.getParameter("courriel"));
        m.setNomFamille(req.getParameter("nom"));
        m.setNomUtilisateur(req.getParameter("username"));
        m.setPrenom(req.getParameter("prenom"));
        m.setTelephone(req.getParameter("telephone"));
        m.setIdVille(req.getParameter("idVillePays"));

        return m;
    }
}